/*
 * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "flutter/shell/platform/ohos/ohos_touch_processor.h"
#include "flutter/lib/ui/window/pointer_data_packet.h"
#include "flutter/shell/platform/ohos/ohos_shell_holder.h"
#include<memory>
#include<cmath>
namespace flutter {

constexpr int MSEC_PER_SECOND = 1000;


PointerData::Change OhosTouchProcessor::getPointerChangeForAction(
    int maskedAction) {
  switch (maskedAction) {
    LOGD(
        "[engine_yxx]OhosTouchProcessor::getPointerChangeForAction "
        ":%{public}d",
        maskedAction);
    case OH_NATIVEXCOMPONENT_DOWN:
      LOGD("[engine_yxx]OH_NATIVEXCOMPONENT_DOWN");
      return PointerData::Change::kDown;
    case OH_NATIVEXCOMPONENT_UP:
      LOGD("[engine_yxx]OH_NATIVEXCOMPONENT_DOWN");
      return PointerData::Change::kUp;
    case OH_NATIVEXCOMPONENT_CANCEL:
      LOGD("[engine_yxx]OH_NATIVEXCOMPONENT_DOWN");
      return PointerData::Change::kCancel;
    case OH_NATIVEXCOMPONENT_MOVE:
      LOGD("[engine_yxx]OH_NATIVEXCOMPONENT_DOWN");
      return PointerData::Change::kMove;
  }
  return PointerData::Change::kCancel;
}

PointerData::DeviceKind OhosTouchProcessor::getPointerDeviceTypeForToolType(
    int toolType) {
  switch (toolType) {
    case OH_NATIVEXCOMPONENT_TOOL_TYPE_FINGER:
      return PointerData::DeviceKind::kTouch;
    case OH_NATIVEXCOMPONENT_TOOL_TYPE_PEN:
      return PointerData::DeviceKind::kStylus;
    case OH_NATIVEXCOMPONENT_TOOL_TYPE_RUBBER:
      return PointerData::DeviceKind::kInvertedStylus;
    case OH_NATIVEXCOMPONENT_TOOL_TYPE_BRUSH:
      return PointerData::DeviceKind::kStylus;
    case OH_NATIVEXCOMPONENT_TOOL_TYPE_PENCIL:
      return PointerData::DeviceKind::kStylus;
    case OH_NATIVEXCOMPONENT_TOOL_TYPE_AIRBRUSH:
      return PointerData::DeviceKind::kStylus;
    case OH_NATIVEXCOMPONENT_TOOL_TYPE_MOUSE:
      return PointerData::DeviceKind::kMouse;
    case OH_NATIVEXCOMPONENT_TOOL_TYPE_LENS:
      return PointerData::DeviceKind::kTouch;
    case OH_NATIVEXCOMPONENT_TOOL_TYPE_UNKNOWN:
      return PointerData::DeviceKind::kTouch;
  }
  return PointerData::DeviceKind::kTouch;
}


void OhosTouchProcessor::HandleTouchEvent(int64_t shell_holderID,OH_NativeXComponent* component,OH_NativeXComponent_TouchEvent* touchEvent) 
{
  LOGD("[engine_yxx]1OhosTouchProcessor::HandleTouchEvent");
  if (touchEvent == nullptr) 
  {
    LOGD("[engine_yxx] 1OhosTouchProcessor::HandleTouchEvent");
    return;
  }
  //用来获取datapoint 数据
  LOGD("[engine_yxx]用来获取datapoint 数据 OhosTouchProcessor::HandleTouchEvent");
  int numPoints = 1;
  numPoints = touchEvent->numPoints;  // 获取触摸事件的触摸点数
  LOGD("[engine_yxx]>>2OhosTouchProcessor::HandleTouchEvent numPoints =:%{public}d",numPoints);
  auto packet = std::make_unique<flutter::PointerDataPacket>(numPoints);  // 构造PointerDataPacket
  if (numPoints >= 1 && numPoints < static_cast<int>(OH_MAX_TOUCH_POINTS_NUMBER)) 
  {

    if (numPoints >= 2 && numPoints < static_cast<int>(OH_MAX_TOUCH_POINTS_NUMBER)) 
    {
      LOGD("[engine_yxx]>>>OhosTouchProcessor::HandleTouchEvent  ,enter two points parts. numPoints =%{public}d",numPoints);
      // 当触摸点大于2个小于OH_MAX_TOUCH_POINTS_NUMBER时获取结构体数组中的点的情况
      for (int i = 0; i < numPoints; i++) 
      {
        LOGD("[engine_yxx]>>>3OhosTouchProcessor::HandleTouchEvent  numPoints =,enter two points parts. :i=%{public}d numPoints=%{public}d",i, numPoints);
        PointerData pointerData;
        pointerData.Clear();
        pointerData.embedder_id =(touchEvent->touchPoints)[i].id;  // 手指的唯一标识符。
        LOGD("[engine_yxx]>>>3OhosTouchProcessor::HandleTouchEvent  numPoints =,enter two points parts.:(touchEvent->touchPoints)[i].id=%{public}d numPoints=%{public}d",
            (touchEvent->touchPoints)[i].id, numPoints);
        pointerData.time_stamp = (touchEvent->touchPoints)[i].timeStamp / MSEC_PER_SECOND;  // 当前触摸事件的时间戳。
        pointerData.change = getPointerChangeForAction((touchEvent->touchPoints)[i].type);  // 触摸事件类型。
        pointerData.physical_y = (touchEvent->touchPoints)[i].y;
        LOGD("[engine_yxx]>>>3OhosTouchProcessor::HandleTouchEvent  numPoints =,enter two points parts. :(touchEvent->touchPoints)[i].y=%{public}f numPoints=%{public}d",
            (touchEvent->touchPoints)[i].y, numPoints);  
        pointerData.physical_x = (touchEvent->touchPoints)[i].x;
        LOGD("[engine_yxx]>>>3OhosTouchProcessor::HandleTouchEvent  numPoints ,enter two points parts. :(touchEvent->touchPoints)[i].x=%{public}f numPoints=%{public}d",
            (touchEvent->touchPoints)[i].x, numPoints);  //

        // Delta will be generated in pointer_data_packet_converter.cc.
        pointerData.physical_delta_x = 0.0;
        pointerData.physical_delta_y = 0.0;
        pointerData.device = (touchEvent->touchPoints)[i].id;
        // Pointer identifier will be generated in
        // pointer_data_packet_converter.cc.
        pointerData.pointer_identifier = 0;
        // XComponent not support Scroll
        pointerData.signal_kind = PointerData::SignalKind::kNone;
        pointerData.scroll_delta_x = 0.0;
        pointerData.scroll_delta_y = 0.0;
        pointerData.pressure = (touchEvent->touchPoints)[i].force;
        pointerData.pressure_max = 1.0;
        pointerData.pressure_min = 0.0;
        OH_NativeXComponent_TouchPointToolType toolType;
        OH_NativeXComponent_GetTouchPointToolType(component, i, &toolType);
        pointerData.kind = getPointerDeviceTypeForToolType(toolType);//source type
        if (pointerData.kind == PointerData::DeviceKind::kTouch)
        {
          if (pointerData.change == PointerData::Change::kDown || pointerData.change == PointerData::Change::kMove) 
          {
            LOGD("[engine_yxx]>>>>4pointerData.buttons = kPointerButtonTouchContact");
            pointerData.buttons = kPointerButtonTouchContact;
          }
        }else if (pointerData.kind == PointerData::DeviceKind::kMouse) 
        {
        }
        pointerData.pan_x = 0.0;
        pointerData.pan_y = 0.0;
        // Delta will be generated in pointer_data_packet_converter.cc.
        pointerData.pan_delta_x = 0.0;
        pointerData.pan_delta_y = 0.0;
        // The contact area between the fingerpad and the screen
        pointerData.size = (touchEvent->touchPoints)[i].size;
		
			  pointerData.scale = 1.0;
        pointerData.rotation = 0.0;
         //传入其他参数
        pointerData.screenx = (touchEvent->touchPoints)[i].screenX;
       LOGD("[engine_yxx]>>>3OhosTouchProcessor::HandleTouchEvent  numPoints ,enter two points parts. :(touchEvent->touchPoints)[i].screenX=%{public}f numPoints=%{public}d",
           (touchEvent->touchPoints)[i].screenX, numPoints);  
       pointerData.screeny = (touchEvent->touchPoints)[i].screenY;
       LOGD("[engine_yxx]>>>3OhosTouchProcessor::HandleTouchEvent  numPoints ,enter two points parts. :(touchEvent->touchPoints)[i].screenY=%{public}f numPoints=%{public}d",
           (touchEvent->touchPoints)[i].screenY, numPoints);  
       
        packet->SetPointerData(i, pointerData);
      }
    } 
    else 
    {
      // 处理只有一个触摸点的情况
      PointerData pointerData;
      pointerData.Clear();
      pointerData.embedder_id = touchEvent->id;  // 手指的唯一标识符。
      pointerData.time_stamp =touchEvent->timeStamp / MSEC_PER_SECOND;  // 当前触摸事件的时间戳。
      pointerData.change =getPointerChangeForAction(touchEvent->type);  // 触摸事件类型。
      pointerData.physical_y = touchEvent->y;           //
      pointerData.physical_x = touchEvent->x;
  // Delta will be generated in pointer_data_packet_converter.cc.
      pointerData.physical_delta_x = 0.0;
      pointerData.physical_delta_y = 0.0;
      pointerData.device = touchEvent->id;
      // Pointer identifier will be generated in
      // pointer_data_packet_converter.cc.
      pointerData.pointer_identifier = 0;
      // XComponent not support Scroll
      pointerData.signal_kind = PointerData::SignalKind::kNone;
      pointerData.scroll_delta_x = 0.0;
      pointerData.scroll_delta_y = 0.0;
      pointerData.pressure = touchEvent->force;
      pointerData.pressure_max = 1.0;
      pointerData.pressure_min = 0.0;
      OH_NativeXComponent_TouchPointToolType toolType;
      OH_NativeXComponent_GetTouchPointToolType(component, 0, &toolType);
      pointerData.kind = getPointerDeviceTypeForToolType(toolType);
      if (pointerData.kind == PointerData::DeviceKind::kTouch) 
      {
        if (pointerData.change == PointerData::Change::kDown || pointerData.change == PointerData::Change::kMove) 
        {
          LOGD("[engine_yxx][one]pointerData.buttons one point  = kPointerButtonTouchContact");
          pointerData.buttons = kPointerButtonTouchContact;
        }
      }
      else if (pointerData.kind == PointerData::DeviceKind::kMouse) 
      {
      }
      pointerData.pan_x = 0.0;
      pointerData.pan_y = 0.0;
      // Delta will be generated in pointer_data_packet_converter.cc.
      pointerData.pan_delta_x = 0.0;
      pointerData.pan_delta_y = 0.0;
      // The contact area between the fingerpad and the screen
      pointerData.size = touchEvent->size;
      pointerData.scale = 1.0;
      pointerData.rotation = 0.0;
      
      pointerData.screenx = touchEvent->screenX;
      pointerData.screeny = touchEvent->screenY;
      LOGD("[engine_yxx][one]one point>>>parts.touchEvent->screenX :=%{public}f ,touchEvent->screenY :=%{public}f numPoints=%{public}d",touchEvent->screenX,touchEvent->screenY,numPoints);  
      packet->SetPointerData(0, pointerData);
    }

  }
  auto ohos_shell_holder = reinterpret_cast<OHOSShellHolder*>(shell_holderID);
  ohos_shell_holder->GetPlatformView()->DispatchPointerDataPacket(std::move(packet));
}

}  // namespace flutter